﻿// LazyRankList.ts
// 通用懒加载排行榜 - 仅传递排名，渲染由 item 自主完成

import Core from "../Core";
import { getGUID } from "../utils/IdUtils";

const { ccclass, property, menu } = cc._decorator;

@ccclass
@menu("通用组件/懒加载/LazyRankList")
export class LazyRankList extends cc.Component {
  @property({ type: cc.Prefab, displayName: "Item 预制体" })
  itemPrefab: cc.Prefab = null;

  @property({ displayName: "总条目数量" })
  totalItems: number = 1000;

  @property({ displayName: "每项高度（垂直）" })
  itemHeight: number = 80;

  @property({ displayName: "每项宽度（水平）" })
  itemWidth: number = 600;

  @property({ displayName: "是否垂直布局" })
  isVertical: boolean = true;

  @property({ displayName: "屏幕内可见数量" })
  visibleCount: number = 6;

  @property({ displayName: "上下/左右缓冲数量" })
  bufferCount: number = 2;

  @property({ displayName: "是否开启入场动画" })
  enableEnterAnimation: boolean = true;

  @property({ displayName: "动画持续时间（秒）" })
  animationDuration: number = 0.5;

  @property({ displayName: "动画延迟间隔（秒）" })
  animationDelay: number = 0.1;
  @property({
    displayName: "定位参考节点（用于'我的排名'居中）",
    type: cc.Node,
  })
  locator: cc.Node = null;

  // 用于动画缓存
  private visibleItemsForAnimation: cc.Node[] = [];
  // 在组件中添加一个私有池（专用于当前列表项）
  private itemPool: cc.NodePool = null;
  private items: { node: cc.Node; rank: number }[] = [];

  private scrollView: cc.ScrollView = null;
  private content: cc.Node = null;
  private startIndex = 0;
  private itemSize = 0;

  protected onEnable(): void {
    // 确保 itemPrefab 存在
    if (!this.itemPrefab) {
      console.error("[LazyRankList] 未设置 itemPrefab！");
      return;
    }

    this.scrollView = this.node.getComponent(cc.ScrollView);
    if (!this.scrollView) {
      console.error("[LazyRankList] 请在节点上添加 ScrollView 组件！");
      return;
    }

    // ✅ 重新获取 content，防止丢失
    this.content = this.scrollView.content;
    if (!this.content) {
      console.error("[LazyRankList] ScrollView.content 为空！");
      return;
    }

    // ✅ 第一步：先设置 content 的锚点和尺寸！（必须在 ScrollView 初始化后立即设置）
    this.content.anchorY = 1; // 垂直布局：顶部对齐
    this.itemSize = this.isVertical ? this.itemHeight : this.itemWidth;
    if (this.itemSize <= 0) {
      this.itemSize = 110;
    }

    // ✅ 立即设置 content 高度，不能晚于 ScrollView 初始化
    const contentSize = this.totalItems * this.itemSize;
    this.content.height = contentSize;
    this.content.width = this.isVertical ? this.content.width : contentSize; // 水平布局

    // ✅ 确保初始位置合法（但不要手动改 y！）
    if (isNaN(this.content.y) || !isFinite(this.content.y)) {
      this.content.y = 0;
    }

    // ✅ 使用 NodePool 专用池（更轻量）
    this.itemPool = new cc.NodePool();
    const key = this.getPrefabKey(this.itemPrefab);

    // ✅ 创建缓冲节点
    this.items = [];
    const totalCount = this.visibleCount + this.bufferCount * 2;
    for (let i = 0; i < totalCount; i++) {
      // ✅ get 会自动根据 prefab 匹配缓存
      let node = this.itemPool.get(this.itemPrefab);
      if (!node) {
        node = cc.instantiate(this.itemPrefab);
      }
      node.parent = this.content;
      this.items.push({ node, rank: -1 });
    }

    // ✅ 初始化列表
    this.updateItems();

    cc.tween(this.node)
      .delay(0)
      .call(() => {
        this.scrollToTopOnInit();
      })
      .start();
    // ✅ 绑定滚动事件
    this.scrollView.node.on("scrolling", this.onScroll, this);
    this.scrollView.node.on("scroll-ended", this.onScrollEnded, this);
  }

  protected onDisable(): void {
    // ✅ 第一步：先停止 ScrollView 并解绑事件
    if (this.scrollView) {
      if (this.scrollView.isScrolling) {
        this.scrollView.stopAutoScroll(); // ✅ 先停止滚动
      }
      this.scrollView.node.off("scrolling", this.onScroll, this);
      this.scrollView.node.off("scroll-ended", this.onScrollEnded, this);
    }
    this.visibleItemsForAnimation.forEach((node) => {
      if (node && node.isValid) {
        node.stopAllActions();
      }
    });
    this.visibleItemsForAnimation = [];
    // ✅ 回收所有 item 节点
    if (this.itemPool) {
      for (let i = 0; i < this.items.length; i++) {
        const item = this.items[i];
        if (item && item.node && item.node.isValid) {
          item.node.removeFromParent();
          item.node.active = false;
          this.itemPool.put(item.node); // ✅ 自动归类
        }
      }
    }
    this.items = [];
    this.unscheduleAllCallbacks();
    if (this.content.childrenCount) {
      this.content.removeAllChildren();
    }
    this.startIndex = 0;
    this.node.stopAllActions();
    //Core.poolManager.putNode(this.node);
  }

  protected onDestroy(): void {
    // ✅ 销毁池子中所有缓存节点（防止内存泄漏）
    if (this.itemPool) {
      this.itemPool.clear(); // 重要：clear 会 destroy 所有缓存节点
      this.itemPool = null;
    }
  }

  private onScroll(): void {
    const scrollOffset = this.scrollView.getScrollOffset();
    const scrollDistance = this.isVertical ? scrollOffset.y : scrollOffset.x;
    // ✅ 限制滚动范围
    const maxScrollable = (this.totalItems - 1) * this.itemSize;
    const clampedScroll = Math.max(0, Math.min(scrollDistance, maxScrollable));
    const newStart = Math.floor(clampedScroll / this.itemSize);

    const bufferSize = this.items.length;
    const maxStart = Math.max(0, this.totalItems - bufferSize);
    const clampedStart = cc.misc.clampf(newStart, 0, maxStart);

    if (clampedStart !== this.startIndex) {
      this.startIndex = clampedStart;
      this.updateItems();
    }
  }

  private updateItems(): void {
    if (this.itemSize <= 0) {
      console.warn("[LazyRankList] itemSize 无效，跳过 updateItems");
      return;
    }
    const safeStartIndex = Math.max(
      0,
      Math.min(this.startIndex, this.totalItems - this.items.length)
    );
    this.startIndex = safeStartIndex;
    for (let i = 0; i < this.items.length; i++) {
      const rank = this.startIndex + i + 1;
      const item = this.items[i];
      if (rank >= 1 && rank <= this.totalItems) {
        item.node.active = true;
        item.node.y = -(this.startIndex + i + 0.5) * this.itemSize;
        const scriptName = item.node.name;
        const script = item.node.getComponent(scriptName);
        if (script && typeof script.refreshUI === "function") {
          script.refreshUI(rank);
        } else {
          console.warn(
            `[LazyRankList] item "${scriptName}" 缺少 refreshUI(rank) 方法`
          );
        }
        item.rank = rank;
      } else {
        console.log(item.rank, "隐藏");
        item.node.active = false;
      }
    }
  }

  /**
   * 外部调用：滚动到我的排名
   * @param myRank 我的排名（1-based）
   */
  public scrollToMyRank(myRank: number): void {
    if (myRank < 1 || myRank > this.totalItems) {
      console.warn(
        `[LazyRankList] 排名 ${myRank} 超出范围 [1, ${this.totalItems}]`
      );
      return;
    }
    const targetOffset = (myRank - 1) * this.itemSize;
    const vec = this.isVertical
      ? cc.v2(0, targetOffset)
      : cc.v2(targetOffset, 0);
    this.scrollView.scrollToOffset(vec, 0.5);
    setTimeout(() => {
      this.updateItems();
    }, 500);
  }

  /**
   * 外部调用：返回顶部
   * @param duration 滚动持续时间（秒），默认 0.3 秒；传 0 表示立即跳转
   */
  public backToTop(duration: number = 0.3): void {
    if (!this.scrollView) {
      console.warn("[LazyRankList] ScrollView 未初始化，无法返回顶部");
      return;
    }
    const targetOffset = cc.v2(0, 0);
    this.scrollView.scrollToOffset(targetOffset, duration);
    this.node.emit("back-to-top-complete");
    //console.log(`✅ [LazyRankList] 已执行返回顶部，耗时: ${duration}s`);
  }

  private onScrollEnded(): void {
    const scrollOffset = this.scrollView.getScrollOffset();
    const scrollDistance = this.isVertical ? scrollOffset.y : scrollOffset.x;
    const newStart = Math.floor(scrollDistance / this.itemSize);
    const maxStart = Math.max(0, this.totalItems - this.items.length);
    const finalStart = cc.misc.clampf(newStart, 0, maxStart);
    if (finalStart !== this.startIndex) {
      this.startIndex = finalStart;
      this.updateItems();
    }
  }

  /**
   * 初始化时滚动到顶部，并准备动画
   */
  private scrollToTopOnInit(): void {
    // ✅ 强制滚动到顶部
    this.scrollView.scrollToOffset(cc.v2(0, 0), 0); // 立即跳转

    // ✅ 重置 startIndex
    this.startIndex = 0;

    // ✅ 重新更新 item 位置
    this.updateItems();

    // ✅ 延迟一帧，确保 item 已排列好
    cc.tween(this.node)
      .delay(1 / 60)
      .call(() => {
        this.collectVisibleItems();
        if (this.enableEnterAnimation) {
          this.playStaggerAnimation();
        }
      })
      .start();
  }

  /**
   * 收集当前可视的 item 节点（用于动画）
   */
  private collectVisibleItems(): void {
    this.visibleItemsForAnimation = [];
    for (let i = 0; i < this.items.length; i++) {
      const item = this.items[i];
      if (item.node.active) {
        this.visibleItemsForAnimation.push(item.node);
      }
    }
  }

  /**
   * 播放 item 的阶梯式入场动画
   */
  private playStaggerAnimation(): void {
    const total = this.visibleItemsForAnimation.length;
    for (let i = 0; i < total; i++) {
      const node = this.visibleItemsForAnimation[i];

      // ✅ 初始状态：隐藏在左边，透明
      node.setPosition(-200, node.y);
      node.opacity = 0;

      // ✅ 执行延迟动画
      cc.tween(node)
        .delay(i * this.animationDelay)
        .to(
          this.animationDuration,
          { x: 0, opacity: 255 },
          { easing: "sineOut" }
        )
        .start();
    }
  }

  //====================工具方法====================
  // 在 LazyRankList.ts 中添加私有方法
  private getPrefabKey(prefab: cc.Prefab): string {
    if (!prefab) {
      console.error("[LazyRankList] Invalid prefab provided!");
      return "";
    }
    // 使用 _uuid 是最安全、唯一的方式
    return prefab.name + getGUID();
  }
}
